package com.hsmpay.mobile.action.account.externalAccessPay;

import com.hsmpay.common.pojo.BasePojo;
import com.hsmpay.common.pojo.qian4.Qian4SendLog;
import com.hsmpay.common.pojo.user.User;
import com.hsmpay.common.util.NumberUtil;
import com.hsmpay.mobile.action.account.officialAccPay.OfficialAccPayBaseAction;
import com.hsmpay.mobile.action.account.scanCodePay.MD5;
import com.hsmpay.mobile.action.account.scanCodePay.ScanCodePayParam;
import com.hsmpay.mobile.action.account.scanCodePay.SignUtils;
import com.hsmpay.mobile.pojo.bank.Bank;
import com.hsmpay.mobile.pojo.other.Settings;
import com.hsmpay.mobile.pojo.terminal.Tchannel;
import com.hsmpay.mobile.pojo.trans.TransOrder;
import com.hsmpay.mobile.pojo.trans.TransPriorSettle;
import com.hsmpay.mobile.service.account.AccountManageQ4Service;
import com.hsmpay.mobile.service.bank.BankService;
import com.hsmpay.mobile.service.other.SettingsService;
import com.hsmpay.mobile.service.trans.Qian4SendLogService;
import com.hsmpay.mobile.service.trans.TransOrderService;
import com.hsmpay.mobile.service.trans.TransPriorSettleService;
import com.hsmpay.mobile.service.trans.TransRefuseCardService;
import com.hsmpay.mobile.service.user.UserTransLimitService;
import com.hsmpay.qian4.pojo.PurchaseResult;
import com.hsmpay.qian4.service.ds.*;
import com.hsmpay.qian4.service.ds.impl.XYScanCodePayServiceImpl;
import com.hsmpay.utils.DesUtil;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.*;

/**
 * Created by zhao on 11/9/16.
 * 开放给外部访问的收款接口
 * 给第三方作为收款通道使用
 */

@Controller("externalAccessPayAction")
@Scope("prototype")
public class ExternalAccessPayAction extends ExternalAccessPayBaseAction{

    private static Logger log = LoggerFactory.getLogger(ExternalAccessPayAction.class);

    @Resource(name = "userTransLimitService")
    protected UserTransLimitService<BasePojo, Long> userTransLimitService;
    @Resource(name = "transRefuseCardService")
    protected TransRefuseCardService<BasePojo, Long> transRefuseCardService;//拒绝卡号交易
    @Resource(name = "transOrderService")
    protected TransOrderService<TransOrder, Long> transOrderService;
    @Resource(name = "accountManageQ4Service")
    protected AccountManageQ4Service<BasePojo, Long> accountManageQ4Service;
    @Resource(name = "qian4SendLogService")
    protected Qian4SendLogService<Qian4SendLog, Long> qian4SendLogService;//发送日志
    @Resource(name = "bankService")
    protected BankService<Bank,Long> bankService;
    @Resource(name="ds_XYScanCodePayService")
    protected XYScanCodePayService ds_XYScanCodePayService;
    @Resource(name="ds_JQScanCodePayService")
    protected JQScanCodePayService ds_JQScanCodePayService;
    @Resource(name="weixinPayService")
    protected WeixinPayService weixinPayService;
    @Resource(name="shangLianChuService")
    protected ShangLianChuPayService shangLianChuPayService;
    @Resource(name = "transPriorSettleService")
    protected TransPriorSettleService<TransPriorSettle, Long> transPriorSettleService;
    @Resource(name="ds_JQSecondPayService")
    protected JQSecondPayService ds_JQSecondPayService;
    @Resource(name="ds_JQQRCodePayService")
    protected JQQRCodePayService ds_JQQRCodePayService;
    @Resource(name = "settingsService")
    protected SettingsService<Settings, Long> settingsService;
    @Resource(name = "ds_JQSDKPayService")
    protected JQSDKPayService ds_JQSDKPayService;

    /**
     * 获取微信OpenId参数
     * @return
     */
    public String getWXCode() throws Exception {
        String merUrl = getRequest().getParameter("merUrl");
        if(StringUtils.isNotBlank(merUrl)){
            merUrl = merUrl.replace(":","%3A").replace("/","%2F").replace("?","%3F").replace("=","%3D");
            String getOpenIdUrl = "http://app.1spay.com/agent/getWxCode.action";
            StringBuffer sb = new StringBuffer();
            sb.append("<script>");
            sb.append("window.location.href=\'"+getOpenIdUrl+"?");
            sb.append("merUrl="+merUrl);
            sb.append("\'</script>");

            log.info("第三方重定向 ====> " + sb.toString());

            try {
                OutputStream os = getResponse().getOutputStream();
                os.write(sb.toString().getBytes("UTF-8"));
                os.flush();
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
                log.error("url重定向异常:{}",e);
            }
        }
        return null;
    }

    /**
     * 支付业务入口
     * @return
     */
    public String exPay(){
        //接收参数
        JSONObject paramJson = new JSONObject();
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(getRequest().getInputStream()));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while((line = br.readLine()) != null){
                sb.append(line);
            }
            log.info("第三方收款请求: " + sb.toString());
            paramJson = JSONObject.fromObject(sb.toString());
        }catch (Exception e){
            log.info("参数不合法: " + e.getMessage());
            sendThirdErrorMsg("6001","参数不合法");
            return null;
        }

        if(paramJson.containsKey("customerNo") && StringUtils.isNotBlank(paramJson.getString("customerNo"))){
            customerNo = paramJson.getString("customerNo");
        }else{
            log.info("支付时, 商户号为空!");
            sendThirdDBMsg("6001","customerNo");
            return null;
        }

        User user = new User();
        user.setId(Long.valueOf(customerNo));
        try {
            user = userService.searchEntity(user);
        } catch (Exception e) {
            log.info("支付时, 获取用户信息异常: " + e.getMessage());
            sendThirdErrorMsg("6001","未获取到商户信息");
            e.printStackTrace();
            return null;
        }
        if(null == user){
            log.info("支付时, 用户不存在!");
            sendThirdErrorMsg("6001","商户不存在");
            return null;
        }

        //校验参数
        if(paramJson.containsKey("version") && StringUtils.isNotBlank(paramJson.getString("version"))){
            version = paramJson.getString("version");
        }else {
            log.info("version参数不能为空");
            sendThirdDBMsg("6001","version");
            return null;
        }

        if(paramJson.containsKey("service") && StringUtils.isNotBlank(paramJson.getString("service"))){
            service = paramJson.getString("service");
        }else {
            log.info("service参数不能为空");
            sendThirdDBMsg("6001","service");
            return null;
        }

        if(paramJson.containsKey("reqDate") && StringUtils.isNotBlank(paramJson.getString("reqDate"))){
            reqDate = paramJson.getString("reqDate");
        }else {
            log.info("reqDate参数不能为空");
            sendThirdDBMsg("6001","reqDate");
            return null;
        }

        if(paramJson.containsKey("transAmount") && StringUtils.isNotBlank(paramJson.getString("transAmount"))){
            transAmount = paramJson.getString("transAmount");
        }else {
            log.info("transAmount参数不能为空");
            sendThirdDBMsg("6001","transAmount");
            return null;
        }

        if(Long.valueOf(transAmount) <= 0){
            log.info("金额不合法");
            sendThirdErrorMsg("6001","金额不合法");
            return null;
        }

        if(paramJson.containsKey("bgReturnUrl") && StringUtils.isNotBlank(paramJson.getString("bgReturnUrl"))){
            bgReturnUrl = paramJson.getString("bgReturnUrl");
        }else {
            log.info("bgReturnUrl参数不能为空");
            sendThirdDBMsg("6001","bgReturnUrl");
            return null;
        }

        if(paramJson.containsKey("externalId") && StringUtils.isNotBlank(paramJson.getString("externalId"))){
            externalId = paramJson.getString("externalId");
        }else {
            log.info("externalId参数不能为空");
            sendThirdDBMsg("6001","externalId");
            return null;
        }

        if(paramJson.containsKey("openId") && StringUtils.isNotBlank(paramJson.getString("openId"))){
            openId = paramJson.getString("openId");
        }

        if(paramJson.containsKey("requestIp") && StringUtils.isNotBlank(paramJson.getString("requestIp"))){
            requestIp = paramJson.getString("requestIp");
        }else {
            log.info("requestIp参数不能为空");
            sendThirdDBMsg("6001","requestIp");
            return null;
        }

        if(paramJson.containsKey("description") && StringUtils.isNotBlank(paramJson.getString("description"))){
            description = paramJson.getString("description");
        }else {
            log.info("description参数不能为空");
            sendThirdDBMsg("6001","description");
            return null;
        }

        if(paramJson.containsKey("reqTime") && StringUtils.isNotBlank(paramJson.getString("reqTime"))){
            reqTime = paramJson.getString("reqTime");
        }else {
            log.info("reqTime参数不能为空");
            sendThirdDBMsg("6001","reqTime");
            return null;
        }

        if(paramJson.containsKey("selfData") && StringUtils.isNotBlank(paramJson.getString("selfData"))){
            selfData = paramJson.getString("selfData");
        }else {
            log.info("selfData参数不能为空");
            sendThirdDBMsg("6001","selfData");
            return null;
        }

        if(paramJson.containsKey("appClient") && StringUtils.isNotBlank(paramJson.getString("appClient"))){
            appClient = paramJson.getString("appClient");
        }

        //校验签名
        if(paramJson.containsKey("sign")){
            if(!SignUtils.checkJsonParam(paramJson, user.getPassword())) {
                log.info("验证签名不通过");
                sendThirdErrorMsg("6001","验证签名不通过");
                return null;
            }
        }

        //去收款
        payOrder(user);

        return null;
    }


    /**
     * 支付
     * @return
     * @throws Exception
     */
    public String payOrder(User user){
        functionKey = SCANCODEPAY_FUNCKEY;
        Qian4SendLog send = null;//发送数据
        TransPriorSettle transPriorSettle = null;
        TransOrder transOrder = null;
        ScanCodePayParam scanCodePayParam = null;
        JSONObject result = null;
        try {
            if (!checkPIV(functionKey)) {
                log.info("银行接口暂停使用！");
                sendThirdErrorMsg("9999","接口暂停使用!");
                return null;
            }
            if (null != user) {
                Object[] resultA = assembleBean(user);
                if (null == resultA) return null;

                send = (Qian4SendLog) resultA[0];
                transOrder = (TransOrder) resultA[1];
                scanCodePayParam = (ScanCodePayParam) resultA[2];

                int channelId = user.getChannelId().intValue();

                if(service.equals("0001")){
                    channelId = OfficialAccPayBaseAction.TC_JQ;
                }else if(service.equals("0002")){
                    channelId = OfficialAccPayBaseAction.TC_JQ_QR;
                }else if(service.equals("0004")){
                    channelId = OfficialAccPayBaseAction.TC_JQ_SDK;
                }else if(service.equals("0010")){
                    if(appClient.equals("1")){
                        channelId = OfficialAccPayBaseAction.TC_JQ_SECOND;
                    }else{
                        Settings settings = settingsService.getSettingsByFk("JQ_SECOND_STATUS");
                        int defaultChannelId = Integer.valueOf(settings.getValue3());
                        channelId = defaultChannelId;
                    }
                }

                Tchannel tc = tchannelService.searchMobileTchannelByCode(channelId);

                send.setCollectionType(tc.getCode());
                send.setRoleId(user.getRoleId());
                double fee = calculateFee(transOrder.getTransMoney(), transOrder.getFeeRate());
                transOrder.setFeeMoney(fee);
                transOrder.setChargeAmount(transOrder.getTransMoney() - fee);
                transOrder.setOrderTypeId(RECEIVABLES);
                //下订单
                transPriorSettle = accountManageQ4Service.advanceOrder(transOrder, send, send.getCollectionType());
                PurchaseResult rs = null;
                switch (send.getCollectionType()){
                    case OfficialAccPayBaseAction.TC_XY:
                        send.setMerchantId(XYScanCodePayServiceImpl.mchId);
                        rs = ds_XYScanCodePayService.purchase(send,scanCodePayParam,signaturePath);
                        break;
                    case OfficialAccPayBaseAction.TC_JQ:
                        rs = ds_JQScanCodePayService.getQRCode(send,scanCodePayParam,signaturePath);
                        break;
                    case OfficialAccPayBaseAction.TC_WEIXIN:
                        rs = weixinPayService.getQRCode(send,scanCodePayParam,signaturePath);
                        break;
                    case OfficialAccPayBaseAction.TC_SHANGLIANCHU:
                        rs = shangLianChuPayService.getQRCode(send,scanCodePayParam,signaturePath);
                        break;
                    case OfficialAccPayBaseAction.TC_JQ_QR:
                        rs = ds_JQQRCodePayService.getQRCode(scanCodePayParam,user);
                        break;
                    case OfficialAccPayBaseAction.TC_JQ_SDK:
                        rs = ds_JQSDKPayService.getPayInfo(scanCodePayParam);
                        break;
                    case OfficialAccPayBaseAction.TC_JQ_SECOND:
                        rs = ds_JQSecondPayService.getQRCode(scanCodePayParam,user,Integer.valueOf(StringUtils.isBlank(appClient)?"0":appClient));
                        break;
                }

                //需要等待回调通知交易结果
                if(send.getCollectionType() == OfficialAccPayBaseAction.TC_JQ
                        || send.getCollectionType() == OfficialAccPayBaseAction.TC_WEIXIN
                        || send.getCollectionType() == OfficialAccPayBaseAction.TC_SHANGLIANCHU
                        || send.getCollectionType() == OfficialAccPayBaseAction.TC_JQ_SECOND
                        || send.getCollectionType() == OfficialAccPayBaseAction.TC_JQ_QR
                        || send.getCollectionType() == OfficialAccPayBaseAction.TC_HSM
                        || send.getCollectionType() == OfficialAccPayBaseAction.TC_JQ_SDK
                        ) {
                    result = new JSONObject();
                    result.put("version","1.0.0");
                    if(rs.getReqCode().equals("0000")){
                        result.put("code", "0");
                    }else {
                        result.put("code", "0001");
                    }
                    result.put("message", rs.getReqMsg());
                    result.put("customerNo", customerNo);
                    result.put("payUrl", rs.getPayUrl());
                    result.put("payImg", rs.getPayImg());
                    result.put("tokenId", rs.getTokenId());
                    result.put("selfData", DesUtil.generate32Key());
                    result.put("appId", rs.getAppId());

                    result.put("timestamp", rs.getTimestamp());
                    result.put("nonceStr", rs.getNonceStr());
                    result.put("prepayId", rs.getPrepayId());
                    result.put("paySign", rs.getPaySign());
                    result.put("payInfo",rs.getPayInfo());

                    SortedMap<String,String> map = new TreeMap<>();
                    Iterator<String> resultItr = result.keys();
                    while (resultItr.hasNext()) {
                        String key = resultItr.next();
                        if(StringUtils.isBlank(result.getString(key))){
                            result.remove(key);
                        }else{
                            map.put(key,result.getString(key));
                        }
                    }

                    Map<String,String> params = SignUtils.paraFilter(map);
                    StringBuilder buf = new StringBuilder((params.size() +1) * 10);
                    SignUtils.buildPayParams(buf,params,false);
                    String preStr = buf.toString();
                    String sign = MD5.sign(preStr, "&key=" + user.getPassword(), "utf-8");
                    result.put("sign", sign);

                    if(!rs.getReqCode().equals("0000")){
                        //获取支付路径失败则直接标记交易失败
                        result = purchaseResolveResult(send, rs, transOrder, transPriorSettle, user, tc);
                    }else {
                        transPriorSettle.setResponseCode("0002");
                        transPriorSettle.setMerchantId(rs.getCustomerNo());
                        transPriorSettle.setBankMessage("订单创建成功,等待用户付款!");
                        transPriorSettleService.updateEntity(transPriorSettle);

//                        if(!ConConfig.isFormal()){
//                            CloseableHttpClient client = null;
//                            String notifyUrl = "http://localhost:8000/proOneMobile/JQNotify.action?code=0&message=交易成功&externalId="+scanCodePayParam.getOutTradeNo();
//                            try {
//                                HttpGet httpGet = new HttpGet(notifyUrl);
//                                client = HttpClients.createDefault();
//                                client.execute(httpGet);
//
//                            }catch (Exception e){
//                                e.printStackTrace();
//                                log.error("【进钱-秒到收款】 系统异常!");
//                                throw e;
//                            }
//                        }
                    }
                }else {
                    //解析结果
                    result = purchaseResolveResult(send, rs, transOrder, transPriorSettle, user, tc);
                    log.debug(result.toString());
                }
                sendThirdMsg(new String(result.toString().getBytes("UTF-8"),"UTF-8"));
            } else {
                log.info("我要收款时, 商户号=" + customerNo + " 对应的商户不存在!");
                sendThirdDBMsg("6012", customerNo + "");
            }
        } catch (Exception e) {
            e.printStackTrace();
            //TODO:异常处理  超时处理
            revocationOrderTimeOut(send, transPriorSettle,scanCodePayParam);
        } finally {
            send = null;
            transPriorSettle = null;
            transOrder = null;
            result = null;
        }
        return null;
    }

    /**
     * 计算手续费
     *
     * @param transMoney
     * @param feeRate
     * @return
     */
    private Double calculateFee(Double transMoney, Double feeRate) {
        double fee = NumberUtil.roundF2(feeRate * transMoney);
        return fee;
    }


}
